package cn.edu.anan.interceptor;

import cn.edu.anan.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;

/**
 * 限流 interceptor
 *
 * @author ThinkPad
 * @version 1.0
 * @date 2021/9/12 8:31
 */
@Component
@Slf4j
public class LimitInterceptor extends HandlerInterceptorAdapter {

 @Autowired
 private RedisUtil redisUtil;

 /**
  * 前置处理
  * @param request
  * @param response
  * @param handler
  * @return
  * @throws Exception
  */
  @Override
  public boolean preHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler) throws Exception {
      // 当前请求url
      String url = request.getRequestURI();

      // 判断请求是否属于方法的请求
      if(handler instanceof HandlerMethod){
          HandlerMethod hm = (HandlerMethod) handler;

          // 检查注解AccessLimit，若没有注解，直接放行
          AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
          if(accessLimit == null){
              log.info("当前正在请求接口：{}，该接口不需要限制访问.", url);
              return true;
          }

          // 过期时间，最大请求次数
          int seconds = accessLimit.seconds();
          int maxCount = accessLimit.maxCount();
          log.info("当前正在请求接口：{}，该接口有访问限制需求，时间：{},最大访问次数：{}",
                  url, seconds, maxCount);

          // 限流key
          String key = "rate:limit" + url;
          key = key.replaceAll("/", ":");
          Integer count = 0;

          // 从redis中获取用户访问的次数
          Object keyValue = redisUtil.get(key);
          if(keyValue != null){
              count = (Integer) keyValue;
          }

          // 第1次访问
          if(count == 0){
              redisUtil.set(key, 1, seconds);
          }else if(count < maxCount){
              // 第2到maxCount-1次访问
              redisUtil.inCr(key,1);
          }else{
              // 大于等于maxCount次访问
              String content = String.format("您正在访问的接口：%s，超出了访问限制阈值：%d",url, maxCount);
              render(response, content);
              return false;

          }


      }

    return true;

  }

  /**
   * 封装返回值
   * @param response
   * @param msg
   * @throws Exception
   */
  private void render(HttpServletResponse response, String msg)throws Exception {
      response.setContentType("application/json;charset=UTF-8");
      OutputStream out = response.getOutputStream();
      out.write(msg.getBytes("UTF-8"));
      out.flush();

      out.close();

  }

}